
#ifndef __LIBERTY_LIBRARY_TASK_H__
#define __LIBERTY_LIBRARY_TASK_H__

#include <Liberty3D/Liberty3D.h>
#include <Liberty3D/Engine/IObjectMethod.h>
#include <Liberty3D/Library/IMutex.h>
#include <exception>

namespace Liberty { namespace Library {
    class TaskScheduler;

    typedef enum {
        TaskExecuteOnMainThread = 0x0001,
        TaskRecurring           = 0x0002,
        TaskBackground          = 0x0004,

        TaskScheduled           = 0x1000,
        TaskRunning             = 0x2000,
        TaskFinished            = 0x4000,
        TaskStatusBits          = 0xf000
    } TaskOptions;

    class Task {
        friend class TaskScheduler;

    protected:
        int                                             _priority;
        volatile unsigned int                           _options;
        std::shared_ptr<Liberty::Engine::IObjectMethod> _method;
        std::vector<boost::any>                         _parameters;
        std::vector<std::shared_ptr<Task>>              _dependsOn;

    protected:
        boost::any      _result;
        std::exception* _exception;

    public:
        Task();
        virtual ~Task();

        bool execute();

    public:
        inline int                                             priority()   const { return _priority; }
        inline unsigned int                                    options()    const { return _options & TaskStatusBits; }
        inline std::shared_ptr<Liberty::Engine::IObjectMethod> method()     const { return _method; }
        inline const std::vector<boost::any>&                  parameters() const { return _parameters; }
        inline const std::vector<std::shared_ptr<Task>>&       dependsOn()  const { return _dependsOn; }

        inline bool isRunning()   const { return (_options & TaskRunning)  == TaskRunning; }
        inline bool hasFinished() const { return (_options & TaskFinished) == TaskFinished; }
        inline bool hasFailed()   const { return _exception != nullptr; }

        inline bool mustExecuteOnMainThread() const { return (_options & TaskExecuteOnMainThread) == TaskExecuteOnMainThread; }

        const boost::any& result() const;

        void setPriority(int);
        void setOptions (unsigned int);
        void setMethod  (const std::shared_ptr<Liberty::Engine::IObjectMethod>&);

        void addParameter (const boost::any&);
        void addParameter (boost::any&&);
        void addDependancy(const std::shared_ptr<Task>&);

        bool isReady() const;
        void waitUntilFinished();
    };
}}

#endif
